/*******************************************************************************
 * @note Copyright (C) 2020 Shanghai Panchip Microelectronics Co., Ltd. All rights reserved.
 *
 * @file pan3028.c
 * @brief
 *
 * @history - V3.0, 2021-11-05
 *******************************************************************************/
#include "Dev_Include.h"

bool pan3028_irq_trigged_flag = false;
uint8_t reg_agc_value[98] = {0x90, 0xff, 0x64, 0x24, 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x24,
							 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x24,
							 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x24, 0x00, 0x03, 0x24, 0x2A,
							 0x20, 0x03, 0x2A, 0x30, 0x40, 0x03, 0x30, 0x36, 0x60, 0x03, 0x36, 0x3B, 0x80, 0x03, 0x3B, 0x41,
							 0x84, 0x03, 0x41, 0x46, 0x88, 0x03, 0x46, 0x4B, 0x8C, 0x03, 0x4B, 0x50, 0x90, 0x03, 0x50, 0x56,
							 0x91, 0x03, 0x56, 0x06, 0xFF, 0x40, 0x42, 0x0F, 0x00, 0x00, 0x01, 0xF4, 0x2F, 0xF3, 0x0F, 0x00, 0x00, 0x00};

/**
 * @brief read one byte from register in current page
 * @param[in] <addr> register address to write
 * @return value read from register
 */
static uint8_t PAN3028_read_reg(uint8_t addr)
{
	uint8_t temreg = 0x00;

	rf_port.spi_cs_low();
	rf_port.spi_readwrite(0x00 | (addr << 1));
	temreg = rf_port.spi_readwrite(0x00);
	rf_port.spi_cs_high();
	return temreg;
}

/**
 * @brief write global register in current page and chick
 * @param[in] <addr> register address to write
 * @param[in] <value> address value to write to rgister
 * @return result
 */
static uint32_t PAN3028_write_reg(uint8_t addr, uint8_t value)
{
	uint16_t tmpreg = 0;
	uint16_t addr_w = (0x01 | (addr << 1));

	rf_port.spi_cs_low();
	rf_port.spi_readwrite(addr_w);
	rf_port.spi_readwrite(value);
	rf_port.spi_cs_high();
	tmpreg = PAN3028_read_reg(addr);
	if (tmpreg == value)
	{
		return OK;
	}
	else
	{
		return FAIL;
	}
}

/**
 * @brief rf send data fifo,send bytes register
 * @param[in] <addr> register address to write
 * @param[in] <buffer> send data buffer
 * @param[in] <size> send data size
 * @return none
 */
static void PAN3028_write_fifo(uint8_t addr, uint8_t *buffer, int size)
{
	int i;
	uint8_t addr_w = (0x01 | (addr << 1));

	rf_port.spi_cs_low();
	rf_port.spi_readwrite(addr_w);
	for (i = 0; i < size; i++)
	{
		rf_port.spi_readwrite(buffer[i]);
	}
	rf_port.spi_cs_high();
}

/**
 * @brief rf receive data fifo,read bytes from register
 * @param[in] <addr> register address to write
 * @param[in] <buffer> receive data buffer
 * @param[in] <size> receive data size
 * @return none
 */
static void PAN3028_read_fifo(uint8_t addr, uint8_t *buffer, int size)
{
	int i;
	uint8_t addr_w = (0x00 | (addr << 1));

	rf_port.spi_cs_low();
	rf_port.spi_readwrite(addr_w);
	for (i = 0; i < size; i++)
	{
		buffer[i] = rf_port.spi_readwrite(0x00);
	}
	rf_port.spi_cs_high();
}

/**
 * @brief switch page
 * @param[in] <page> page to switch
 * @return result
 */
static uint32_t PAN3028_switch_page(enum PAGE_SEL page)
{
	uint8_t page_sel = 0x00;
	uint8_t tmpreg = 0x00;

	tmpreg = PAN3028_read_reg(REG_SYS_CTL);
	page_sel = (tmpreg & 0xfc) | page;
	PAN3028_write_reg(REG_SYS_CTL, page_sel);
	if ((PAN3028_read_reg(REG_SYS_CTL) & 0x03) == page)
	{
		return OK;
	}
	else
	{
		return FAIL;
	}
}

/**
 * @brief This function write a value to register in specific page
 * @param[in] <page> the page of register
 * @param[in] <addr> register address
 * @param[in] <value> value to write
 * @return result
 */
uint32_t PAN3028_write_spec_page_reg(enum PAGE_SEL page, uint8_t addr, uint8_t value)
{
	if (PAN3028_switch_page(page) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_reg(addr, value) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief read a value to register in specific page
 * @param[in] <page> the page of register
 * @param[in] <addr> register address
 * @return success(register value) or failure
 */
uint8_t PAN3028_read_spec_page_reg(enum PAGE_SEL page, uint8_t addr)
{
	if (PAN3028_switch_page(page) != OK)
	{
		return FAIL;
	}
	return PAN3028_read_reg(addr);
}

/**
 * @brief write continue register valuies(buffer) in specific addr page
 * @param[in] <page> the page of register
 * @param[in] <addr> register start address
 * @param[in] <buffer> values to write
 * @param[in] <len> buffer len
 * @return result
 */
uint32_t PAN3028_write_read_continue_regs(enum PAGE_SEL page, uint8_t addr, uint8_t *buffer, uint8_t len)
{
	uint8_t i, temreg[256];
	uint16_t addr_w;
	if (PAN3028_switch_page(page) != OK)
	{
		return FAIL;
	}

	addr_w = (0x01 | (addr << 1));
	rf_port.spi_cs_low();
	rf_port.spi_readwrite(addr_w);
	for (i = 0; i < len; i++)
	{
		rf_port.spi_readwrite(buffer[i]);
	}
	rf_port.spi_cs_high();

	rf_port.spi_cs_low();
	rf_port.spi_readwrite(0x00 | (addr << 1));
	for (i = 0; i < len; i++)
	{
		temreg[i] = rf_port.spi_readwrite(0x00);
	}
	rf_port.spi_cs_high();

	for (i = 0; i < len; i++)
	{
		if (temreg[i] != buffer[i])
		{
			return FAIL;
		}
	}
	return OK;
}

/**
 * @brief PAN3028 clear all irq
 * @param[in] <none>
 * @return result
 */
uint8_t PAN3028_clr_irq(void)
{
	uint8_t clr_cnt = 0;
	uint16_t a = 0, b = 0;
	while (clr_cnt < 3)
	{
		PAN3028_write_spec_page_reg(PAGE0_SEL, 0x6C, 0x1f); // clr irq
		if (PAN3028_read_spec_page_reg(PAGE0_SEL, 0x6C) == 0)
		{
			return OK;
		}
		else
		{
			clr_cnt++;
			for (a = 0; a < 1200; a++) // 10ms
				for (b = 0; b < 100; b++)
					;
			continue;
		}
	}
	return FAIL;
}

/**
 * @brief get irq status
 * @param[in] <none>
 * @return ira status
 */
uint8_t PAN3028_get_irq(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x6C);

	return tmpreg;
}

/**
 * @brief software reset
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_rst(void)
{
	uint8_t tmpreg = 0;

	tmpreg = PAN3028_read_reg(REG_SYS_CTL);
	tmpreg |= 0x80;
	PAN3028_write_reg(REG_SYS_CTL, tmpreg);

	tmpreg = PAN3028_read_reg(REG_SYS_CTL);
	tmpreg &= 0x7F;

	PAN3028_write_reg(REG_SYS_CTL, tmpreg);

	return OK;
}

/**
 * @brief clear packet count register
 * @param[in] <none>
 * @return none
 */
void PAN3028_clr_pkt_cnt(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_reg(REG_SYS_CTL);
	tmpreg = (tmpreg & 0xbf) | 0x40;
	PAN3028_write_reg(REG_SYS_CTL, tmpreg);

	tmpreg = PAN3028_read_reg(REG_SYS_CTL);
	tmpreg = (tmpreg & 0xbf);
	PAN3028_write_reg(REG_SYS_CTL, tmpreg);
}

/**
 * @brief enable AGC function
 * @param[in] <state>
 *			  AGC_OFF/AGC_ON
 * @return result
 */
uint32_t PAN3028_agc_enable(uint32_t state)
{
	uint8_t reg_val = 0x02;

	if (state == AGC_OFF)
	{
		reg_val = 0x03;
	}
	else
	{
		reg_val = 0x02;
	}

	if (PAN3028_write_spec_page_reg(PAGE2_SEL, 0x06, reg_val) != OK)
	{
		return FAIL;
	}

	return OK;
}

/**
 * @brief configure AGC function
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_agc_config(void)
{
	return PAN3028_write_read_continue_regs(PAGE2_SEL, 0x07, reg_agc_value, 98);
}

/**
 * @brief do basic configuration to initialize
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_init(void)
{
	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x06, 0x01) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x1f, 0x18) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x20, 0x15) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x23, 0x08) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x25, 0x08) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x27, 0x04) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x28, 0x14) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x2d, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x2e, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x2f, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x30, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x31, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x32, 0x60) != OK) // HIGH
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x33, 0x07) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x3e, 0x2c) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x3c, 0xff) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x40, 0x50) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4c, 0xbf) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4d, 0x0e) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x55, 0x02) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x0e, 0x44) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x0f, 0x0a) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x1e, 0x00) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x11, 0xA1) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x15, 0x38) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x2f, 0x0c) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x38, 0x02) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x57, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x58, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x59, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x5a, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x5b, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x5c, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x5d, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x5e, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x5f, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x60, 0x33) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x61, 0x11) != OK)
	{
		return FAIL;
	}

	//	if(PAN3028_write_spec_page_reg(PAGE1_SEL, 0x67, 0xc0)  != OK)/*add PA*/
	//	{
	//		return FAIL;
	//	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x06, 0x26) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x10, 0x80) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x11, 0x0d) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x12, 0x16) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x18, 0xff) != OK)
	{
		return FAIL;
	}

	return OK;
}

/**
 * @brief change PAN3028 mode from deep sleep to standby3(STB3)
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_deepsleep_wakeup(void)
{
	uint8_t rstreg = 0, porreg = 0;

	porreg = PAN3028_read_reg(0x04);
	porreg |= 0x10;
	PAN3028_write_reg(0x04, porreg);
	rf_port.delayus(10);
	porreg &= 0xEF;
	PAN3028_write_reg(0x04, porreg);

	rstreg = PAN3028_read_reg(REG_SYS_CTL);
	rstreg &= 0x7F;
	PAN3028_write_reg(REG_SYS_CTL, rstreg);
	rf_port.delayus(10);
	rstreg |= 0x80;
	PAN3028_write_reg(REG_SYS_CTL, rstreg);
	rf_port.delayus(10);
	rstreg &= 0x7F;
	PAN3028_write_reg(REG_SYS_CTL, rstreg);
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_DEEP_SLEEP) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_SLEEP) != OK)
	{
		return FAIL;
	}
	rf_port.delayms(1);

	if (PAN3028_write_reg(0x03, 0x1b) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_reg(0x04, 0x76) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x26, 0x40) != OK)
	{
		return FAIL;
	}

	rf_port.tcxo_init();
	rf_port.delayms(1);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB1) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB2) != OK)
	{
		return FAIL;
	}
	rf_port.delayms(1);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB3) != OK)
	{
		return FAIL;
	}
	else
	{
		rf_port.delayus(10);
		return OK;
	}
}

/**
 * @brief change PAN3028 mode from sleep to standby3(STB3)
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_sleep_wakeup(void)
{
	rf_port.delayus(10);
	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_SLEEP) != OK)
	{
		return FAIL;
	}
	rf_port.delayms(1);

	if (PAN3028_write_reg(0x03, 0x1b) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_reg(0x04, 0x76) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x26, 0x40) != OK)
	{
		return FAIL;
	}

	rf_port.tcxo_init();
	rf_port.delayms(1);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB1) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB2) != OK)
	{
		return FAIL;
	}
	rf_port.delayms(1);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB3) != OK)
	{
		return FAIL;
	}
	else
	{
		rf_port.delayus(10);
		return OK;
	}
}

/**
 * @brief change PAN3028 mode from standby3(STB3) to deep sleep, PAN3028 should set DCDC_OFF before enter deepsleep
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_deepsleep(void)
{
	rf_port.delayus(10);
	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB3) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB2) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB1) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	rf_port.tcxo_close();

	if (PAN3028_write_reg(0x04, 0x06) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_SLEEP) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_DEEP_SLEEP) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief change PAN3028 mode from standby3(STB3) to sleep, PAN3028 should set DCDC_OFF before enter sleep
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_sleep(void)
{
	rf_port.delayus(10);
	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB3) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB2) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_STB1) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	rf_port.tcxo_close();

	if (PAN3028_write_reg(0x04, 0x16) != OK)
	{
		return FAIL;
	}
	rf_port.delayus(10);

	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_SLEEP) != OK)
	{
		return FAIL;
	}
	else
	{
		rf_port.delayus(10);
		return OK;
	}
}

/**
 * @brief set LO frequency
 * @param[in] <lo> LO frequency
 *			  LO_400M / LO_800M
 * @return result
 */
uint32_t PAN3028_set_lo_freq(uint32_t lo)
{
	uint32_t reg_val = 0;
	reg_val = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x45);
	reg_val &= ~(0x03);

	if (lo == LO_400M)
	{
		reg_val |= 0x02;
	}
	else
	{
		reg_val |= 0x01;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x45, reg_val) != OK)
	{
		return FAIL;
	}
	return OK;
}

/**
 * @brief set frequence
 * @param[in] <freq>  RF frequency(in Hz) to set
 * @return result
 */
uint32_t PAN3028_set_freq(uint32_t freq)
{
	uint8_t reg_read;
	uint8_t reg_freq;
	uint32_t tmp_var = 0;
	uint32_t integer_part = 0;
	uint32_t fractional_part = 0;
	uint8_t lowband_sel = 0;
	int fb, fc;

	if ((freq >= freq_360000000) && (freq <= freq_370000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x0f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25;
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000;
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq >= freq_370000000) && (freq <= freq_385000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x2f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25;
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000;
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq >= freq_385000000) && (freq <= freq_405000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x4f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25;
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000;
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq > freq_405000000) && (freq <= freq_430000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x6f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25;
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000;
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq > freq_430000000) && (freq <= freq_460000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x8f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25;
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000;
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq > freq_460000000) && (freq <= freq_495000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0xaf) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25;
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000;
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq > freq_495000000) && (freq <= freq_535000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0xcf) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25;
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000;
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq > freq_535000000) && (freq <= freq_600000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0xef) != OK)
		{
			return FAIL;
		}
		lowband_sel = 1;
		tmp_var = freq / 1000 * 25; // freq * 4 * 1.0 / 16000000,-5
		integer_part = tmp_var / 100000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 100000;
		fc = (fractional_part * 4) / 1000; // lowband_sel = 1,1600/4,-5+2
		PAN3028_set_lo_freq(LO_400M);
	}
	else if ((freq >= freq_720000000) && (freq <= freq_740000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x0f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125; // freq * 2 * 1.0 / 16000000,-6
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000; // lowband_sel = 0,1600/4,-6+2
		PAN3028_set_lo_freq(LO_800M);
	}
	else if ((freq >= freq_740000000) && (freq <= freq_770000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x2f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125;
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000;
		PAN3028_set_lo_freq(LO_800M);
	}
	else if ((freq > freq_770000000) && (freq <= freq_810000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x4f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125;
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000;
		PAN3028_set_lo_freq(LO_800M);
	}
	else if ((freq > freq_810000000) && (freq <= freq_860000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x6f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125;
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000;
		PAN3028_set_lo_freq(LO_800M);
	}
	else if ((freq > freq_860000000) && (freq <= freq_920000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0x8f) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125;
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000;
		PAN3028_set_lo_freq(LO_800M);
	}
	else if ((freq > freq_920000000) && (freq <= freq_990000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0xaf) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125;
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000;
		PAN3028_set_lo_freq(LO_800M);
	}
	else if ((freq > freq_990000000) && (freq <= freq_1070000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0xcf) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125;
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000;
		PAN3028_set_lo_freq(LO_800M);
	}
	else if ((freq > freq_1070000000) && (freq <= freq_1200000000))
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0xef) != OK)
		{
			return FAIL;
		}
		lowband_sel = 0;
		tmp_var = freq / 1000 * 125;
		integer_part = tmp_var / 1000000;
		fb = integer_part - 20;
		fractional_part = tmp_var % 1000000;
		fc = (fractional_part * 8) / 10000;
		PAN3028_set_lo_freq(LO_800M);
	}
	else
	{
		return FAIL;
	}

	if ((freq >= freq_360000000) && (freq <= freq_600000000))
	{
		if (fc < 0xff)
		{
			fb = fb - 1;
			fc = fc + 400;
		}
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x15, (fb & 0x7F)) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x16, (fc & 0xff)) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x17, ((fc >> 8) & 0x0f)) != OK)
	{
		return FAIL;
	}

	reg_read = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x18);
	reg_read &= ~((1 << 2) | (1 << 1));
	reg_read |= (1 << 3) | (lowband_sel << 2) | (lowband_sel << 1);

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x18, reg_read) != OK)
	{
		return FAIL;
	}

	reg_freq = freq & 0xff;
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x09, reg_freq) != OK)
	{
		return FAIL;
	}

	reg_freq = (freq >> 8) & 0xff;
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0a, reg_freq) != OK)
	{
		return FAIL;
	}

	reg_freq = (freq >> 16) & 0xff;
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0b, reg_freq) != OK)
	{
		return FAIL;
	}

	reg_freq = (freq >> 24) & 0xff;
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0c, reg_freq) != OK)
	{
		return FAIL;
	}

	return OK;
}

/**
 * @brief read frequency(in Hz)
 * @param[in] <none>
 * @return frequency(in Hz)
 */
uint32_t PAN3028_read_freq(void)
{
	uint8_t reg1, reg2, reg3, reg4;
	uint32_t freq = 0x00;

	reg1 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x09);
	reg2 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0a);
	reg3 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0b);
	reg4 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0c);
	freq = (reg4 << 24) | (reg3 << 16) | (reg2 << 8) | reg1;
	return freq;
}

/**
 * @brief calculate tx time
 * @param[in] <none>
 * @return tx time(ms)
 */
uint32_t PAN3028_calculate_tx_time(void)
{
	int bw_val;
	float tx_done_time;
	uint8_t pl = PAN3028_read_spec_page_reg(PAGE1_SEL, REG_PAYLOAD_LEN);
	uint8_t sf = PAN3028_get_sf();
	uint8_t crc = PAN3028_get_crc();
	uint8_t code_rate = PAN3028_get_code_rate();
	uint8_t bw = PAN3028_get_bw();

	float a, b, c, d = 0.00;
	if (bw == 6)
	{
		bw_val = 62500;
	}
	if (bw == 7)
	{
		bw_val = 125000;
	}
	if (bw == 8)
	{
		bw_val = 250000;
	}
	if (bw == 9)
	{
		bw_val = 500000;
	}
	a = (float)(8 * pl - 4 * sf + 28 + 16 * crc) / (float)(4 * sf);
	b = ceil(a);
	c = code_rate + 4;
	d = ((float)((2 << (sf - 1))) / bw_val);
	tx_done_time = (12.25 + 8 + b * c) * d * 1000;

	return tx_done_time + 5;
}

/**
 * @brief set bandwidth
 * @param[in] <bw_val> value relate to bandwidth
 *		      BW_62_5K / BW_125K / BW_250K / BW_500K
 * @return result
 */
uint32_t PAN3028_set_bw(uint32_t bw_val)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;
	temp_val_1 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0d);
	temp_val_2 = ((temp_val_1 & 0x0F) | (bw_val << 4));
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0d, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief read bandwidth
 * @param[in] <none>
 * @return bandwidth
 */
uint8_t PAN3028_get_bw(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0d);

	return (tmpreg & 0xff) >> 4;
}

/**
 * @brief set spread factor
 * @param[in] <sf> spread factor to set
 *		      SF_7 / SF_8 / SF_9 / SF_10 / SF_11 / SF_12
 * @return result
 */
uint32_t PAN3028_set_sf(uint32_t sf_val)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	if (sf_val < 7 || sf_val > 12)
	{
		return FAIL;
	}
	else
	{
		temp_val_1 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0e);
		temp_val_2 = ((temp_val_1 & 0x0F) | (sf_val << 4));
		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0e, temp_val_2) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
}

/**
 * @brief read Spreading Factor
 * @param[in] <none>
 * @return Spreading Factor
 */
uint8_t PAN3028_get_sf(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0e);

	return (tmpreg & 0xff) >> 4;
}

/**
 * @brief set payload CRC
 * @param[in] <crc_val> CRC to set
 *		      CRC_ON / CRC_OFF
 * @return result
 */
uint32_t PAN3028_set_crc(uint32_t crc_val)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	temp_val_1 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0e);
	temp_val_2 = ((temp_val_1 & 0xF7) | (crc_val << 3));
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0e, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief read payload CRC
 * @param[in] <none>
 * @return CRC status
 */
uint8_t PAN3028_get_crc(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0e);

	return (tmpreg & 0x08) >> 3;
}

/**
 * @brief set code rate
 * @param[in] <code_rate> code rate to set
 *			  CODE_RATE_45 / CODE_RATE_46 / CODE_RATE_47 / CODE_RATE_48
 * @return result
 */
uint32_t PAN3028_set_code_rate(uint8_t code_rate)
{
	uint8_t tmpreg = 0;

	tmpreg = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0d);
	tmpreg &= ~(0x7 << 1);
	tmpreg |= (code_rate << 1);
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0d, tmpreg) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief get code rate
 * @param[in] <none>
 * @return code rate
 */
uint8_t PAN3028_get_code_rate(void)
{
	uint8_t code_rate = 0;
	uint8_t tmpreg = 0;

	tmpreg = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0d);
	code_rate = ((tmpreg & 0x0e) >> 1);

	return code_rate;
}

/**
 * @brief set rf mode
 * @param[in] <mode>
 *			  PAN3028_MODE_DEEP_SLEEP / PAN3028_MODE_SLEEP
 *            PAN3028_MODE_STB1 / PAN3028_MODE_STB2
 *            PAN3028_MODE_STB3 / PAN3028_MODE_TX / PAN3028_MODE_RX
 * @return result
 */
uint32_t PAN3028_set_mode(uint8_t mode)
{
	if (PAN3028_write_reg(REG_OP_MODE, mode) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief get rf mode
 * @param[in] <none>
 * @return mode
 *		   PAN3028_MODE_DEEP_SLEEP / PAN3028_MODE_SLEEP
 *         PAN3028_MODE_STB1 / PAN3028_MODE_STB2
 *         PAN3028_MODE_STB3 / PAN3028_MODE_TX / PAN3028_MODE_RX
 */
uint8_t PAN3028_get_mode(void)
{
	return PAN3028_read_reg(REG_OP_MODE);
}

/**
 * @brief set rf Tx mode
 * @param[in] <mode>
 *			  PAN3028_TX_SINGLE/PAN3028_TX_CONTINOUS
 * @return result
 */
uint32_t PAN3028_set_tx_mode(uint8_t mode)
{
	uint8_t tmp;
	tmp = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x06);
	tmp = tmp & (~(1 << 2));
	tmp = tmp | (mode << 2);

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x06, tmp) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set rf Rx mode
 * @param[in] <mode>
 *			  PAN3028_RX_SINGLE/PAN3028_RX_SINGLE_TIMEOUT/PAN3028_RX_CONTINOUS
 * @return result
 */
uint32_t PAN3028_set_rx_mode(uint8_t mode)
{
	uint8_t tmp;
	tmp = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x06);
	tmp = tmp & (~(3 << 0));
	tmp = tmp | (mode << 0);

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x06, tmp) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set timeout for Rx. It is useful in PAN3028_RX_SINGLE_TIMEOUT mode
 * @param[in] <timeout> rx single timeout time(in ms)
 * @return result
 */
uint32_t PAN3028_set_timeout(uint32_t timeout)
{
	uint8_t timeout_lsb = 0;
	uint8_t timeout_msb = 0;

	if (timeout > 0xffff)
	{
		timeout = 0xffff;
	}

	timeout_lsb = timeout & 0xff;
	timeout_msb = (timeout >> 8) & 0xff;

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x07, timeout_lsb) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x08, timeout_msb) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief get snr value
 * @param[in] <none>
 * @return snr
 */
float PAN3028_get_snr(void)
{
	float snr_val = 0.0;
	uint8_t sig_pow_l, sig_pow_m, sig_pow_h;
	uint8_t noise_pow_l, noise_pow_m, noise_pow_h;
	uint32_t sig_pow_val;
	uint32_t noise_pow_val;
	uint32_t sf_val;

	sig_pow_l = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x74);
	sig_pow_m = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x75);
	sig_pow_h = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x76);
	sig_pow_val = ((sig_pow_h << 16) | (sig_pow_m << 8) | sig_pow_l);

	noise_pow_l = PAN3028_read_spec_page_reg(PAGE2_SEL, 0x71);
	noise_pow_m = PAN3028_read_spec_page_reg(PAGE2_SEL, 0x72);
	noise_pow_h = PAN3028_read_spec_page_reg(PAGE2_SEL, 0x73);
	noise_pow_val = ((noise_pow_h << 16) | (noise_pow_m << 8) | noise_pow_l);

	sf_val = (PAN3028_read_spec_page_reg(PAGE1_SEL, 0x7c) & 0xf0) >> 4;

	if (noise_pow_val == 0)
	{
		noise_pow_val = 1;
	}

	snr_val = (float)(10 * log10((sig_pow_val / pow(2, sf_val)) / noise_pow_val));

	return snr_val;
}

/**
 * @brief get rssi value
 * @param[in] <none>
 * @return rssi
 */
float PAN3028_get_rssi(void)
{
	float rssi_val;
	int rssi_mix_val;
	int bw_pow_val;

	float snr;
	float Pn;

	int bw_val = PAN3028_get_bw();

	switch (bw_val)
	{
	case 6:
		bw_pow_val = 15;
		break;
	case 7:
		bw_pow_val = 12;
		break;
	case 8:
		bw_pow_val = 9;
		break;
	case 9:
		bw_pow_val = 6;
		break;
	}

	snr = PAN3028_get_snr();

	if (snr < 6)
	{
		Pn = bw_pow_val - 0.9 * snr;
		rssi_mix_val = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x7e);
		rssi_val = (float)rssi_mix_val - 256 - Pn;
	}
	else
	{
		rssi_mix_val = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x7e);
		rssi_val = rssi_mix_val - 256;
	}

	return rssi_val;
}

/**
 * @brief set PA2_IB
 * @param[in] <mode> PA2_IB
 * @return result
 */
uint32_t PAN3028_set_PA2_IB(uint8_t mode)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	temp_val_1 = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x4B);
	temp_val_2 = ((temp_val_1 & 0xF0) | (mode << 3));

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4B, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set PA1_IB
 * @param[in] <mode> PA1_IB
 * @return result
 */
uint32_t PAN3028_set_PA1_IB(uint8_t mode)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	temp_val_1 = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x43);
	temp_val_2 = ((temp_val_1 & 0xF0) | (mode << 3));

#if defined(JAP_915)
	temp_val_2 = 0xf2;
#endif

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x43, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set LDO_TX_VSEL
 * @param[in] <mode> LDO_TX_VSEL
 * @return result
 */
uint32_t PAN3028_set_LDO_TX_VSEL(uint8_t mode)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;
	temp_val_1 = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x35);
	temp_val_2 = ((temp_val_1 & 0xF8) | mode);

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x35, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set pwr
 * @param[in] <tx_power> PA_PWR
 * @return result
 */
uint32_t PAN3028_set_PWR(uint8_t tx_power)
{
	return PAN3028_write_spec_page_reg(PAGE1_SEL, 0x63, tx_power);
}

/**
 * @brief set tx_power
 * @param[in] <tx_power> Reference datasheet for tx_power parameter description
 * @return result
 */
uint32_t PAN3028_set_tx_power(uint8_t tx_power)
{
	if (tx_power == 0)
	{
		if (PAN3028_set_PWR(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA2_IB(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA1_IB(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_LDO_TX_VSEL(0) != OK)
		{
			return FAIL;
		}
	}
	else if (tx_power == 1)
	{
		if (PAN3028_set_PWR(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA2_IB(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA1_IB(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_LDO_TX_VSEL(3) != OK)
		{
			return FAIL;
		}
	}
	else if (tx_power == 2)
	{
		if (PAN3028_set_PWR(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA2_IB(0) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA1_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_LDO_TX_VSEL(3) != OK)
		{
			return FAIL;
		}
	}
	else if ((tx_power > 2) && (tx_power < 11))
	{
		if (PAN3028_set_PWR(tx_power - 3) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA2_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA1_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_LDO_TX_VSEL(3) != OK)
		{
			return FAIL;
		}
	}
	else if ((tx_power > 10) && (tx_power < 25))
	{
		if (PAN3028_set_PWR(((tx_power - 10) << 4) | 0x07) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA2_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA1_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_LDO_TX_VSEL(3) != OK)
		{
			return FAIL;
		}
	}
	else if (tx_power == 25)
	{
		if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x63, 0xE7) != OK)
		{
			return FAIL;
		}
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x35, 0x1F) != OK)
		{
			return FAIL;
		}
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x43, 0xF1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4B, 0x4F) != OK)
		{
			return FAIL;
		}
	}
	else if (tx_power == 26)
	{
		if (PAN3028_set_PWR(((tx_power - 11) << 4) | 0x07) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA2_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA1_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_LDO_TX_VSEL(3) != OK)
		{
			return FAIL;
		}
	}
	else if ((tx_power > 26) && (tx_power < 31))
	{
		if (PAN3028_set_PWR(0xf7) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA2_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_PA1_IB(1) != OK)
		{
			return FAIL;
		}
		if (PAN3028_set_LDO_TX_VSEL(tx_power - 23) != OK)
		{
			return FAIL;
		}
	}
	else
	{
		return FAIL;
	}

	return OK;
}

/**
 * @brief get tx_power
 * @param[in] <none>
 * @return tx_power
 */
uint32_t PAN3028_get_tx_power(void)
{
	uint8_t pa_1st_pwr, pa_2nd_pwr, pa1, pa1_reg_val, pa2, pa2_reg_val, ldo, ldo_reg_val, txpower;

	pa_2nd_pwr = (PAN3028_read_spec_page_reg(PAGE1_SEL, 0x63) & 0xf0) >> 4;
	pa_1st_pwr = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x63) & 0x0f;
	pa1_reg_val = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x43) & 0x0f;
	pa2_reg_val = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x4B) & 0x0f;
	ldo_reg_val = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x35) & 0x07;

	if ((pa_2nd_pwr == 0x0e) && (pa_1st_pwr == 0x07) && (pa1_reg_val == 0x01) && (pa2_reg_val == 0x0f) && (ldo_reg_val == 0x07))
	{
		return 25;
	}

	if (pa2_reg_val)
	{
		pa2 = 1;
	}
	else
	{
		pa2 = 0;
	}

	if (pa1_reg_val)
	{
		pa1 = 1;
	}
	else
	{
		pa1 = 0;
	}

	if (ldo_reg_val)
	{
		ldo = ldo_reg_val - 2;
	}
	else
	{
		ldo = 0;
	}

	txpower = pa_2nd_pwr + pa_1st_pwr + pa2 + pa1 + ldo;

	if (txpower > 24)
	{
		return (txpower + 1);
	}
	else
	{
		return txpower;
	}
}

/**
 * @brief set preamble
 * @param[in] <reg> preamble
 * @return result
 */
uint32_t PAN3028_set_preamble(uint16_t reg)
{
	uint8_t tmp_value;

	tmp_value = reg & 0xff;

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, tmp_value) != OK)
	{
		return FAIL;
	}

	tmp_value = (reg >> 8) & 0xff;
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, tmp_value) != OK)
	{
		return FAIL;
	}
	return OK;
}

/**
 * @brief set RF GPIO as input
 * @param[in] <gpio_pin>  pin number of GPIO to be enable
 * @return result
 */
uint32_t PAN3028_set_gpio_input(uint8_t gpio_pin)
{
	uint8_t tmpreg = 0;

	if (gpio_pin < 8)
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x63);
		tmpreg |= (1 << gpio_pin);
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x63, tmpreg) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
	else
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x64);
		tmpreg |= (1 << (gpio_pin - 8));
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x64, tmpreg) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
}
/**
 * @brief read RF GPIO status
 * @param[in] <gpio_pin>  pin number of GPIO to be enable
 * @return result
 */
uint8_t PAN3028_get_gpio_state(uint8_t gpio_pin)
{
	uint8_t tmpreg = 0;

	if (gpio_pin < 6)
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x74);
	}
	else
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x75);
		gpio_pin -= 6;
	}

	return (tmpreg >> gpio_pin) & 0x01;
}

/**
 * @brief set RF GPIO as output
 * @param[in] <gpio_pin>  pin number of GPIO to be enable
 * @return result
 */
uint32_t PAN3028_set_gpio_output(uint8_t gpio_pin)
{
	uint8_t tmpreg = 0;

	if (gpio_pin < 8)
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x65);
		tmpreg |= (1 << gpio_pin);
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x65, tmpreg) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
	else
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x66);
		tmpreg |= (1 << (gpio_pin - 8));
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x66, tmpreg) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
}

/**
 * @brief set GPIO output state, SET or RESET
 * @param[in] <gpio_pin>  pin number of GPIO to be opearted
 *            <state>   0  -  reset,
 *                      1  -  set
 * @return result
 */
uint32_t PAN3028_set_gpio_state(uint8_t gpio_pin, uint8_t state)
{
	uint8_t tmpreg = 0;

	if (gpio_pin < 8)
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x67);

		if (state == 0)
		{
			tmpreg &= ~(1 << gpio_pin);
		}
		else
		{
			tmpreg |= (1 << gpio_pin);
		}

		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x67, tmpreg) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
	else
	{
		tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x68);

		if (state == 0)
		{
			tmpreg &= ~(1 << (gpio_pin - 8));
		}
		else
		{
			tmpreg |= (1 << (gpio_pin - 8));
		}

		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x68, tmpreg) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
}

/**
 * @brief CAD function enable
 * @param[in] <threshold>
			  CAD_DETECT_THRESHOLD_0A / CAD_DETECT_THRESHOLD_10 / CAD_DETECT_THRESHOLD_15 / CAD_DETECT_THRESHOLD_20
 * @return  result
 */
uint32_t PAN3028_cad_en(uint8_t threshold)
{
	PAN3028_set_gpio_output(11);

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x0f, threshold) != OK)
	{
		return FAIL;
	}
	return OK;
}

/**
 * @brief CAD function disable
 * @param[in] <none>
 * @return  result
 */
uint32_t PAN3028_cad_off(void)
{
	uint8_t tmpreg = 0;

	tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x66);
	tmpreg &= 0xf7;
	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x66, tmpreg) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x0f, 0x0a) != OK)
	{
		return FAIL;
	}
	return OK;
}

/**
 * @brief set rf syncword
 * @param[in] <sync> syncword
 * @return result
 */
uint32_t PAN3028_set_syncword(uint32_t sync)
{
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x0f, sync) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief read rf syncword
 * @param[in] <none>
 * @return syncword
 */
uint8_t PAN3028_get_syncword(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x0f);

	return tmpreg;
}

/**
 * @brief send one packet
 * @param[in] <buff> buffer contain data to send
 * @param[in] <len> the length of data to send
 * @return result
 */
uint32_t PAN3028_send_packet(uint8_t *buff, uint32_t len)
{
	if (PAN3028_write_spec_page_reg(PAGE1_SEL, REG_PAYLOAD_LEN, len) != OK)
	{
		return FAIL;
	}
	if (PAN3028_write_reg(REG_OP_MODE, PAN3028_MODE_TX) != OK)
	{
		return FAIL;
	}
	else
	{
		PAN3028_write_fifo(REG_FIFO_ACC_ADDR, buff, len);
		return OK;
	}
}

/**
 * @brief receive a packet in non-block method, it will return 0 when no data got
 * @param[in] <buff> buffer provide for data to receive
 * @return length, it will return 0 when no data got
 */
uint8_t PAN3028_recv_packet(uint8_t *buff)
{
	uint32_t len = 0;

	len = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x7D);
	PAN3028_read_fifo(REG_FIFO_ACC_ADDR, buff, len);

	/* clear rx done irq */
	PAN3028_clr_irq();

	return len;
}

/**
 * @brief set early interruption
 * @param[in] <earlyirq_val> PLHD IRQ to set
 *		      PLHD_IRQ_ON / PLHD_IRQ_OFF
 * @return result
 */
uint32_t PAN3028_set_early_irq(uint32_t earlyirq_val)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	temp_val_1 = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x2d);
	temp_val_2 = ((temp_val_1 & 0x7f) | (earlyirq_val << 7));

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x2d, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief read plhd irq status
 * @param[in] <none>
 * @return plhd irq status
 */
uint8_t PAN3028_get_early_irq(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x2d);

	return tmpreg;
}

/**
 * @brief set plhd
 * @param[in] <addr> PLHD start addr,Range:0..7f
 *		      <len> PLHD len
 *			  PLHD_LEN8 / PLHD_LEN16
 * @return result
 */
uint32_t PAN3028_set_plhd(uint8_t addr, uint8_t len)
{
	uint8_t temp_val_2;

	temp_val_2 = ((addr & 0x7f) | (len << 7));

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x2e, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief read plhd status
 * @param[in] <none>
 * @return plhd status
 */
uint8_t PAN3028_get_plhd(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE1_SEL, 0x2e);

	return ((tmpreg & 0x80) >> 7);
}

/**
 * @brief set plhd mask
 * @param[in] <plhd_val> plhd mask to set
 *		      PLHD_ON / PLHD_OFF
 * @return result
 */
uint32_t PAN3028_set_plhd_mask(uint32_t plhd_val)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	temp_val_1 = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x58);
	temp_val_2 = ((temp_val_1 & 0xef) | (plhd_val << 4));

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x58, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief read plhd mask
 * @param[in] <none>
 * @return plhd mask
 */
uint8_t PAN3028_get_plhd_mask(void)
{
	uint8_t tmpreg;

	tmpreg = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x58);

	return tmpreg;
}

/**
 * @brief receive 8 bytes plhd data
 * @param[in] <buff> buffer provide for data to receive
 * @return result
 */
uint8_t PAN3028_recv_plhd8(uint8_t *buff)
{
	uint32_t i, len = 8;
	for (i = 0; i < len; i++)
	{
		buff[i] = PAN3028_read_spec_page_reg(PAGE2_SEL, 0x76 + i);
	}

	PAN3028_clr_irq();
	return len;
}

/**
 * @brief receive 16 bytes plhd data
 * @param[in] <buff> buffer provide for data to receive
 * @return result
 */
uint8_t PAN3028_recv_plhd16(uint8_t *buff)
{
	uint32_t i, len = 16;
	for (i = 0; i < len; i++)
	{
		if (i < 10)
		{
			buff[i] = PAN3028_read_spec_page_reg(PAGE2_SEL, 0x76 + i);
		}
		else
		{
			buff[i] = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x76 + i - 10);
		}
	}

	PAN3028_clr_irq();
	return len;
}

/**
 * @brief receive a packet in non-block method, it will return 0 when no data got
 * @param[in] <buff> buffer provide for data to receive
 *			  <len> PLHD_LEN8 / PLHD_LEN16
 * @return result
 */
uint32_t PAN3028_plhd_receive(uint8_t *buf, uint8_t len)
{
	if (len == PLHD_LEN8)
	{
		return PAN3028_recv_plhd8(buf);
	}
	else if (len == PLHD_LEN16)
	{
		return PAN3028_recv_plhd16(buf);
	}
	return FAIL;
}

/**
 * @brief set dcdc mode, The default configuration is DCDC_OFF, PAN3028 should set DCDC_OFF before enter sleep/deepsleep
 * @param[in] <dcdc_val> dcdc switch
 *		      DCDC_ON / DCDC_OFF
 * @return result
 */
uint32_t PAN3028_set_dcdc_mode(uint32_t dcdc_val)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	temp_val_1 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x1e);
	temp_val_2 = ((temp_val_1 & 0xfe) | (dcdc_val << 0));

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x1e, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set LDR mode
 * @param[in] <mode> LDR switch
 *		      LDR_ON / LDR_OFF
 * @return result
 */
uint32_t PAN3028_set_ldr(uint32_t mode)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;

	temp_val_1 = PAN3028_read_spec_page_reg(PAGE3_SEL, 0x12);
	temp_val_2 = ((temp_val_1 & 0xF7) | (mode << 3));
	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x12, temp_val_2) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set preamble by Spreading Factor,It is useful in all_sf_search mode
 * @param[in] <sf> Spreading Factor
 * @return result
 */
uint32_t PAN3028_set_all_sf_preamble(uint32_t sf)
{
	switch (sf)
	{
	case 7:
		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, 0) != OK)
		{
			return FAIL;
		}

		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, 128) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}

	case 8:
		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, 0) != OK)
		{
			return FAIL;
		}

		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, 80) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}

	case 9:
		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, 0) != OK)
		{
			return FAIL;
		}

		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, 48) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}

	case 10:
		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, 0) != OK)
		{
			return FAIL;
		}

		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, 24) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}

	case 11:
		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, 0) != OK)
		{
			return FAIL;
		}

		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, 16) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}

	case 12:
		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, 0) != OK)
		{
			return FAIL;
		}

		if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, 12) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}

	default:
		return FAIL;
	}
}

/**
 * @brief open all sf auto-search mode
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_set_all_sf_search(void)
{
	uint8_t tmp_val;

	tmp_val = (PAN3028_read_spec_page_reg(PAGE3_SEL, 0x12) | 0x01);

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x12, tmp_val) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x2d, 0x07) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x06, 0x01) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, 0xaf) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE1_SEL, 0x0f, 0x0a) != OK)
	{
		return FAIL;
	}
	return OK;
}

/**
 * @brief close all sf auto-search mode
 * @param[in] <none>
 * @return result
 */
uint32_t PAN3028_set_all_sf_search_off(void)
{
	uint8_t tmp_val;

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x14, 0) != OK)
	{
		return FAIL;
	}

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x13, 8) != OK)
	{
		return FAIL;
	}

	tmp_val = (PAN3028_read_spec_page_reg(PAGE3_SEL, 0x12) & 0xFE);

	if (PAN3028_write_spec_page_reg(PAGE3_SEL, 0x12, tmp_val) != OK)
	{
		return FAIL;
	}
	else
	{
		return OK;
	}
}

/**
 * @brief set rf vco
 * @param[in] <mode>
 *			  PAN3028_MODE_TX / PAN3028_MODE_RX
 * @return result
 */
uint32_t PAN3028_set_vco(uint8_t mode)
{
	uint8_t temp_val_1;
	uint8_t temp_val_2;
	temp_val_1 = PAN3028_read_spec_page_reg(PAGE0_SEL, 0x4a);

	if (mode == PAN3028_MODE_TX)
	{
		temp_val_2 = ((temp_val_1 & 0xEF) | (1 << 4));
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, temp_val_2) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
	else if (mode == PAN3028_MODE_RX)
	{
		temp_val_2 = (temp_val_1 & 0xEF);
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x4a, temp_val_2) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
	else
	{
		return FAIL;
	}
}

/**
 * @brief set rf lna gain
 * @param[in] <mode>
 *			  LNA_GAIN_LOW / LNA_GAIN_HIGH
 * @return result
 */
uint32_t PAN3028_set_lna_gain(uint8_t mode)
{
	if (mode == LNA_GAIN_LOW)
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x32, 0) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
	else if (mode == LNA_GAIN_HIGH)
	{
		if (PAN3028_write_spec_page_reg(PAGE0_SEL, 0x32, 0x60) != OK)
		{
			return FAIL;
		}
		else
		{
			return OK;
		}
	}
	else
	{
		return FAIL;
	}
}

/**
 * @brief RF IRQ server routine, it should be call at ISR of IRQ pin
 * @param[in] <none>
 * @return <none>
 */
void PAN3028_irq_handler(void)
{
	pan3028_irq_trigged_flag = true;
}
